# -*- coding: utf8 -*-

from threading import current_thread, RLock

from project.db import database
from project.models import Option, Directory, File, HashFile, Hash, Image, ImageVector10, ImageVector100
from sqlalchemy import func


class Project( object ):

    _sessions = None
    _lock = None

    def __init__( self ):
        self._sessions = {}
        self._lock = RLock()

    def connect( self ):
        database.init({
            "dialect" : "mysql",
            "connection" : "%s:%s@%s" % ("root", "root", "localhost"),
            "database" : "filedup",
            "options" : "?charset=utf8"
        })
        self.create()
        return

    def close_sessions(self):
        for ssid, sess in self._sessions.items():
            sess.close()
            sess.connection().close()
            sess.bind.dispose()
        self._sessions = {}

    def get_session( self ):
        self._lock.acquire()
        sess_id = "sess_%s" % id( current_thread() )
        # print("sess_id=%r" % sess_id)
        if not self._sessions.has_key( sess_id ):
            self._sessions[ sess_id ] = database.getSession()
        self._lock.release()
        return self._sessions[ sess_id ]

    def close_session( self ):
        self._lock.acquire()
        sess_id = "sess_%s" % id( current_thread() )
        # print("sess_id=%r" % sess_id)
        if self._sessions.has_key( sess_id ):
            sess = self._sessions[ sess_id ]
            sess.close()
            sess.connection().close()
            sess.bind.dispose()
            del self._sessions[ sess_id ]
        self._lock.release()
        return

    def create( self ):
        Option.metadata.create_all(database.getEngine())
        return


    def save_option( self, name, value ):
        sess = self.get_session()
        item = sess.query(Option).filter_by(name=name).first()
        if not item:
            item = Option(name, value)
        else:
            item.name = name
            item.value = value
        sess.add(item)
        sess.commit()
        return item

    def get_option( self, name ):
        sess = self.get_session()
        item = sess.query(Option).filter_by(name=name).first()
        return item


    def get_options( self ):
        sess = self.get_session()
        opts = {}
        for item in sess.query(Option).all():
            opts[ item.name ] = item.value
        return opts


    def save_directory( self, parent_id, device, name ):
        """
        Save new directory or replace old with NOTINDEXED status

        @return: object
        @rtype: Directory
        """

        sess = self.get_session()
        item = Directory( parent_id, device, name )

        sess.add(item)
        sess.commit()
        # sess.refresh(item)
        return item

    def insert_file( self, parent_id, device, mime, size, mtime, name ):
        """
        @param parent_id: ID
        @type parent_id: int
        """
        sess = self.get_session()

        item = File( parent_id, device, mime, size, mtime, name )
        sess.add(item)
        sess.commit()
        # sess.refresh(item)
        return item


    def get_file_full_path( self, item ):
        """
        @param item:
        @type item: File
        """
        sess = self.get_session()
        return item.get_full_path( sess )


    def remove_file( self, file_id ):
        sess = self.get_session()
        item = sess.query(File).filter_by(id=file_id).first()
        if item:
            sess.delete(item)
            sess.commit()
        return


    def clean( self ):
        
        HashFile.__table__.drop(database.getEngine(), True)
        Hash.__table__.drop(database.getEngine(), True)
        File.__table__.drop(database.getEngine(), True)
        Directory.__table__.drop(database.getEngine(), True)
        Image.__table__.drop(database.getEngine(), True)
        ImageVector10.__table__.drop(database.getEngine(), True)
        ImageVector100.__table__.drop(database.getEngine(), True)

        self.create()
        
        return


    def insert_hash( self, file_id, hash ):
        sess = self.get_session()

        h = Hash(hash)
        sess.add(h)
        sess.commit()
        # sess.refresh(h)

        hf = HashFile(h.id, file_id)
        sess.add(hf)
        sess.commit()

        return h


    def update_hash( self, hitem, file_id ):
        sess = self.get_session()

        hf = sess.query(HashFile).filter_by(file_id=file_id, hash_id=hitem.id).first()
        if not hf:
            hf = HashFile(hitem.id, file_id)
            sess.add(hf)
            sess.commit()
        return hitem


    def find_hash( self, hash ):
        sess = self.get_session()
        return sess.query(Hash).filter_by(value=hash).first()


    def get_file_hash_id( self, file_id ):
        sess = self.get_session()
        hf = sess.query(HashFile).filter_by(file_id=file_id).first()
        if hf:
            return hf.hash_id
        return None


    def get_nonuniq_files(self):
        """
        @return: [ { "file":<File>, "hash":<Hash> },.. ]
        @rtype: list
        """
        sess = self.get_session()
        hash_ids = []
        for item in sess.query(HashFile).group_by(HashFile.hash_id).having(func.count(HashFile.file_id)>1).all():
            hash_ids.append(item.hash_id)

        file_hash = {}
        if len(hash_ids):
            for item in sess.query(HashFile).filter(HashFile.hash_id.in_(hash_ids)).all():
                file_hash [ str(item.file_id) ] = item.hash_id

        result = []
        if len(file_hash):
            files = sess.query(File).filter(File.id.in_(file_hash.keys())).all()
            hashes = sess.query(Hash).filter(Hash.id.in_(file_hash.values())).all()

            for item in files:

                hash_id = file_hash[ str(item.id) ]

                for hash in hashes:
                    if hash.id == hash_id:
                        result.append({"file":item,"hash":hash})
                        break

        return result


    def get_hash_file_ids( self, hash_id ):
        sess = self.get_session()
        ids = []
        for item in sess.query(HashFile).filter_by(hash_id=hash_id):
            ids.append(item.file_id)
        return ids



    def insert_image( self, file_id, name, animation, mime, size, is_gray,
                      width, height, mode, mean_gray ):
        sess = self.get_session()

        item = Image( file_id, name, animation, mime, size, is_gray,
            width, height, mode, mean_gray )
        sess.add(item)
        sess.commit()
        return item


    def insert_image_v10( self, image_id, orientation,
                          v0, v1, v2, v3, v4, v5, v6, v7, v8, v9 ):
        sess = self.get_session()

        item = ImageVector10(
            image_id, orientation,
            v0, v1, v2, v3, v4, v5, v6, v7, v8, v9
        )
        sess.add(item)
        sess.commit()
        return item

    def insert_image_v100( self, image_id, orientation,
                          vector_str ):
        sess = self.get_session()

        item = ImageVector100(
            image_id, orientation,
            vector_str
        )
        sess.add(item)
        sess.commit()
        return item

    pass
